/*
 * Copyright (c) 2018-2999 九五云信息科技有限公司 All rights reserved.
 *
 * https://www.gz-yami.com/
 *
 */

package com.yami.shop.service.impl;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import cn.hutool.poi.excel.StyleSet;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.yami.shop.bean.model.Category;
import com.yami.shop.bean.model.RetailProd;
import com.yami.shop.bean.model.Supplier;
import com.yami.shop.bean.param.RetailProdExportParam;
import com.yami.shop.bean.param.RetailProdParam;
import com.yami.shop.common.exception.YamiShopBindException;
import com.yami.shop.common.util.Arith;
import com.yami.shop.common.util.PageParam;
import com.yami.shop.common.util.PoiExcelUtil;
import com.yami.shop.dao.RetailProdMapper;
import com.yami.shop.dao.SkuRetailMapper;
import com.yami.shop.dao.SupplierMapper;
import com.yami.shop.service.CategoryService;
import com.yami.shop.service.OrderRetailProdLogService;
import com.yami.shop.service.RetailProdService;
import com.yami.shop.service.SupplierService;
import lombok.AllArgsConstructor;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.usermodel.XSSFDataValidation;
import org.omg.CORBA.INTERNAL;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 *
 *
 * @author LGH
 * @date 2020-08-24 15:18:35
 */
@Service
@AllArgsConstructor
public class RetailProdServiceImpl extends ServiceImpl<RetailProdMapper, RetailProd> implements RetailProdService {

    private final RetailProdMapper retailProdMapper;
    private final CategoryService categoryService;
    private final SupplierMapper supplierMapper;
    private final SkuRetailMapper skuRetailMapper;
    private final Snowflake snowflake;
    private final OrderRetailProdLogService orderRetailProdLogService;

    @Override
    public IPage<RetailProd> getPage(PageParam<RetailProd> page, RetailProd retailProd) {
        return retailProdMapper.getPage(page, retailProd);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeRetainProdByIds(Long[] ids, Long shopId) {
        for (Long id : ids) {
            // 查看id是否与其他商品关联
            int a = skuRetailMapper.countRelationProd(id,shopId);
            if (a > 0) {
                throw new YamiShopBindException("yami.retail.isRelation");
            }
        }
        retailProdMapper.removeRetainProdByIds(ids,shopId);
    }

    @Override
    public boolean countBarCode(String barCode) {
        int nums = retailProdMapper.countBarCode(barCode);
        // nums > 0 表示barcode已经存在
        if (nums > 0) {
            // 单品条码已经存在
            throw new YamiShopBindException("yami.bar.code.exist");
        }
        return nums > 0;
    }

    @Override
    public void countBarCodeAndId(String barCode, Long retailProdId) {
        int nums = retailProdMapper.countBarCodeAndId(barCode,retailProdId);
        if (nums > 0) {
            // 单品条码已经存在
            throw new YamiShopBindException("yami.bar.code.exist");
        }
    }

    @Override
    public RetailProd getInfo(Long retailProdId) {
        return retailProdMapper.getInfo(retailProdId);
    }

    @Override
    public List<RetailProdParam> getBySkuId(Long skuId) {
        List<RetailProdParam> skuSingleProds = retailProdMapper.getBySkuId(skuId);
        for (RetailProdParam skuSingleProd : skuSingleProds) {
            skuSingleProd.setTotal(Arith.round(Arith.mul(skuSingleProd.getRetailNums(),skuSingleProd.getCostPrice()),2));
        }
        return skuSingleProds;
    }

    @Override
    public void exportRetailProd(RetailProd retailProd, HttpServletResponse response, Long shopId) {
        // 根据条件查询出单品
        retailProd.setShopId(shopId);
        List<RetailProdExportParam> list = retailProdMapper.selectByParam(retailProd);
        exportExcel(list,response,shopId);

    }

    @Override
    public void importRetailProdModel(HttpServletResponse response, Long shopId) {
        exportExcel(null,response,shopId);
    }

    @Override
    public Object parseFile(MultipartFile file, Long shopId) throws IOException {
        //读取工作簿
        Workbook workBook = WorkbookFactory.create(file.getInputStream());
        // * 2.1不是Excel文件，直接返回提示信息
        if (!(file.getOriginalFilename().contains("xls") || file.getOriginalFilename().contains("xlsx"))) {
            // 格式错误
            throw  new YamiShopBindException("yami.file.error");
        }
        //读取工作表
        Sheet sheet = workBook.getSheetAt(0);
        int rowNums = sheet.getPhysicalNumberOfRows();
        //校验是否填写内容
        if (rowNums <= 2) {
            // 文件无内容
            throw new YamiShopBindException("yami.document.no.content");
        }
        // 获取店铺分类map
        List<Category> shopCategories = categoryService.listByShopId(shopId);
        // 如果重复的key取最后一个的值
        Map<String, Long> shopCategoryMap = shopCategories.stream().collect(Collectors.toMap(Category::getCategoryName, Category::getCategoryId,(key1 , key2)-> key2));
        // 获取供应商map
        List<Supplier> suppliers = supplierMapper.getByShopId(shopId);
        Map<String, Long> supplierMap = suppliers.stream().collect(Collectors.toMap(Supplier::getSupplierName, Supplier::getSupplierId, (key1, key2) -> key2));
        // 总计导入数据条数
        int total = 0;
        int errorCount = 0;
        //循环读取每一行数据并校验
        List<RetailProd> retailProds = new ArrayList<>();
        Date date = new Date();
        for (int i = 2; i < rowNums; i++) {
            total++;
            try {
                //读取行
                Row row = sheet.getRow(i);
                int cell = 0;
                String[] header = {"单品名称", "单品条码", "单品规格", "单品分类",
                        "单品成本", "单品库存", "单品单位","供应商名称"};
                // 单品名称
                CellType cellType = row.getCell(cell).getCellType();
                String name;
                if(Objects.equals(CellType.NUMERIC,cellType)){
                    name = Objects.isNull(row.getCell(cell))? "":String.valueOf(row.getCell(cell).getNumericCellValue());
                }else {
                    name = Objects.isNull(row.getCell(cell))? "":row.getCell(cell).getStringCellValue();
                }
                // 单品条码
                String barCode = getStringValueByRowAndCell(row, ++cell);
                // 单品规格
                String spec = getStringValueByRowAndCell(row, ++cell);
                // 单品分类
                String categoryName = getStringValueByRowAndCell(row, ++cell);
                // 单品成本
                Double costPrice = Objects.isNull(row.getCell(++cell))? 0.0:row.getCell(cell).getNumericCellValue();
                // 单品库存
                Integer stocks = Objects.isNull(row.getCell(++cell))? 0: (int)row.getCell(cell).getNumericCellValue();
                // 单品单位
                String unit = getStringValueByRowAndCell(row, ++cell);
                // 供应商名称
                String supplierName = getStringValueByRowAndCell(row, ++cell);
                RetailProd retailProd = new RetailProd();
                retailProd.setShopId(shopId);
                retailProd.setBarCode(genBarCode(barCode));
                retailProd.setName(name);
                retailProd.setSpec(spec);
                retailProd.setCategoryId(shopCategoryMap.get(categoryName));
                retailProd.setUnit(unit);
                retailProd.setCostPrice(costPrice);
                retailProd.setStocks(stocks);
                retailProd.setSupplierId(supplierMap.get(supplierName));
                retailProd.setStatus(1);
                retailProd.setCreateTime(date);
                retailProds.add(retailProd);
            } catch (Exception e) {
                errorCount++;
                //错误信息提示
                return "第" + (i + 1) + "行数据有错误," + e.getMessage();
            }
        }
        workBook.close();
        if (CollectionUtils.isNotEmpty(retailProds)) {
            saveBatch(retailProds);
            return "检查到" + total + "条商品，成功导入" + (retailProds.size()) + "条商品信息！错误" + errorCount + "条商品信息！";
        }
        if (total > 0) {
            return "检查到" + total + "条商品，成功导入" + retailProds.size() + "条商品信息！错误" + errorCount + "条商品信息！";
        }
        return  "数据错误!导入0条";
    }

    /**
     * 根据行，n列，判断如果是数值转成字符串
     */
    private String getStringValueByRowAndCell(Row row, int cell) {
        String value;
        if (Objects.isNull(row.getCell(cell))) {
            return "";
        }
        if(Objects.equals(CellType.NUMERIC,row.getCell(cell).getCellType())){
            value = row.getCell(cell).getNumericCellValue() + StrUtil.EMPTY;
        } else {
            value = row.getCell(cell).getStringCellValue();
        }
        return value;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateAndUpdateStock(RetailProd retailProd) {
        RetailProd retailProd1 = retailProdMapper.selectById(retailProd.getRetailProdId());
        retailProdMapper.updateInfoById(retailProd);
        // 如果库存发生改变，就更新相关组合商品得sku库存和商品库存
        if (!Objects.equals(retailProd1.getStocks(),retailProd.getStocks())) {
            Long retailProdId = retailProd.getRetailProdId();
            orderRetailProdLogService.returnStocksByRetailProdIds(Collections.singletonList(retailProdId));
        }
        return true;
    }

    private String genBarCode(String barCode) {
        if (StrUtil.isNotBlank(barCode)) {
            // 判断是否该单品条码已经存在
            countBarCode(barCode);
            return barCode;
        }
       return StringUtils.join("P",String.valueOf(snowflake.nextId()));
    }

    private void exportExcel(List<RetailProdExportParam> list, HttpServletResponse response, Long shopId) {
        //通过工具类创建writer
        ExcelWriter writer = ExcelUtil.getBigWriter();
        // 商品导出or模板
        List<String> headerList;
        String[] header = {"单品名称", "单品条码", "单品规格", "单品分类",
                "单品成本", "单品库存", "单品单位","供应商名称"};
        headerList = Arrays.asList(header);
        Sheet sheet = writer.getSheet();
        writer.merge(headerList.size() - 1, "单品信息表");
        writer.writeRow(headerList);
        sheet.setColumnWidth(0, 20 * 256);

        // 列表设置为文本格式
        CellStyle style = writer.createCellStyle();
        Workbook wb = writer.getWorkbook();
        DataFormat format = wb.createDataFormat();
        style.setDataFormat(format.getFormat("@"));

        sheet.setColumnWidth(0, 40 * 256);
        sheet.setDefaultColumnStyle(0,style);
        sheet.setColumnWidth(1, 40 * 256);
        sheet.setDefaultColumnStyle(1,style);
        sheet.setColumnWidth(2, 20 * 256);
        sheet.setDefaultColumnStyle(2,style);
        sheet.setColumnWidth(3, 20 * 256);
        sheet.setDefaultColumnStyle(3,style);
        sheet.setColumnWidth(4, 20 * 256);
        sheet.setColumnWidth(5, 20 * 256);
        sheet.setColumnWidth(6, 20 * 256);
        sheet.setColumnWidth(7, 40 * 256);
        sheet.setDefaultColumnStyle(6,style);
        sheet.setDefaultColumnStyle(7,style);
        // 商家分类限制
        List<Category> shopCategories = categoryService.listByShopId(shopId);
        if (CollectionUtils.isNotEmpty(shopCategories)) {
            List<String> categoryNames = shopCategories.stream().map(Category::getCategoryName).collect(Collectors.toList());
            createDropDownList(sheet, categoryNames, 2, 50000, 3, 3);
        }
        // 供应商名称
        List<Supplier> suppliers = supplierMapper.getByShopId(shopId);
        if (CollectionUtils.isNotEmpty(suppliers)) {
            List<String> supplierNames = suppliers.stream().map(Supplier::getSupplierName).collect(Collectors.toList());
            createDropDownList(sheet, supplierNames, 2, 50000, 7, 7);
        }
        // 如果要导出的数据为空，导出一个模板
        if (CollectionUtils.isEmpty(list)) {
            PoiExcelUtil.writeExcel(response, writer);
            return;
        }
        int row = 1;
        int size = list.size();
        for (RetailProdExportParam param : list) {
            int firstRow = row + 1;
            int lastRow = row + 1;
            int col = -1;
//            // 单品序号
//            PoiExcelUtil.mergeIfNeed(writer, firstRow, lastRow, ++col, col,row);
            // 单品名称
            PoiExcelUtil.mergeIfNeed(writer, firstRow, lastRow, ++col, col,param.getName());
            // 单品条码
            PoiExcelUtil.mergeIfNeed(writer, firstRow, lastRow, ++col, col,param.getBarCode());
            // 单品规格
            PoiExcelUtil.mergeIfNeed(writer, firstRow, lastRow, ++col, col,param.getSpec());
            // 单品分类
            PoiExcelUtil.mergeIfNeed(writer, firstRow, lastRow, ++col, col,param.getCategoryName());
            // 单品成本
            PoiExcelUtil.mergeIfNeed(writer, firstRow, lastRow, ++col, col,param.getCostPrice());
            // 单品库存
            PoiExcelUtil.mergeIfNeed(writer, firstRow, lastRow, ++col, col,param.getStocks());
            // 单品单位
            PoiExcelUtil.mergeIfNeed(writer, firstRow, lastRow, ++col, col,param.getUnit());
            // 供应商名称
            PoiExcelUtil.mergeIfNeed(writer, firstRow, lastRow, ++col, col,param.getSupplierName());
            row++;
        }
        PoiExcelUtil.writeExcel(response, writer);
    }

    /**
     * 创建下拉列表选项
     *
     * @param sheet    所在Sheet页面
     * @param list   下拉框的选项值
     * @param firstRow 起始行（从0开始）
     * @param lastRow  终止行（从0开始）
     * @param firstCol 起始列（从0开始）
     * @param lastCol  终止列（从0开始）
     */
    private void createDropDownList(Sheet sheet, List<String> list, int firstRow, int lastRow, int firstCol, int lastCol) {
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        DataValidationHelper helper = sheet.getDataValidationHelper();
        CellRangeAddressList addressList = new CellRangeAddressList(firstRow, lastRow, firstCol, lastCol);
        String[] values =list.toArray(new String[list.size()]);
        // 设置下拉框数据
        DataValidationConstraint constraint = helper.createExplicitListConstraint(values);

        DataValidation dataValidation = helper.createValidation(constraint, addressList);
        // Excel兼容性问题
        if (dataValidation instanceof XSSFDataValidation) {
            dataValidation.setSuppressDropDownArrow(true);
            dataValidation.setShowErrorBox(true);
        } else {
            dataValidation.setSuppressDropDownArrow(false);
        }

        sheet.addValidationData(dataValidation);
    }

}
